/* A wacky combination of Brownian Motion, Schelling's segregation model, and
   emergent worm tunnels. */

float threshold = .7; // Threshold for "diversity" between 0 and 1
int hoodRadius = 3;    // How large is a cell's neighborhood
float hoodSize = hoodRadius * ((hoodRadius+3)*2.0);

/* Display variables */
int cellSize = 1;
int cellsX = 400;
int cellsY = 400;

/* The world */
int[][] grid = new int[cellsX][cellsY];

/* Our groups */
color poor  = #EE22EE;
color rich  = #22EE22;

/* Click to start */
void setup() {
  background(#FFFFFF);
  noStroke();
  size(cellsX*cellSize, cellsY*cellSize, P2D);
  seedGrid();
  colorGrid();
  noLoop();
}

void draw() {
  shuffle();
  colorGrid();
}

void mousePressed() {
  setup();
}

void keyPressed() {
  loop();
}

void seedGrid() {
  for(int x = 0; x < cellsX; x++) {
    for(int y = 0; y < cellsY; y++) {    
      grid[x][y] = (x % 2);
    }
  }
}

void colorGrid() {
  for(int x = 0; x < cellsX; x++) {
    for(int y = 0; y < cellsY; y++) {
      if(grid[x][y] == 0) {
        fill(poor);
      } else {
        fill(rich);
      }
      rect(x*cellSize,y*cellSize,cellSize,cellSize);  
    }
  }
}

void shuffle() {
  for(int x = 0; x < cellsX; x++) {
    for(int y = 0; y < cellsY; y++) {
      int others = numDifferent(x,y);
      if(others/hoodSize >= threshold) {
        move(x,y);
      }
    }
  }
}

int numDifferent(int x, int y) {
  int different = 0;
  for(int i = x-hoodRadius; i <= x+hoodRadius; i++) {
    for(int j = y-hoodRadius; j <= y+hoodRadius; j++) {
      if(grid[x][y] != grid[(i+cellsX)%cellsX][(j+cellsY)%cellsY]) {
        if(grid[(i+cellsX)%cellsX][(j+cellsY)%cellsY] != -1) {
          different++;
        }
      }
    }
  }
  return different;
}

void move(int x, int y) {
  int newX = (int)random(-2,2);
  int newY = (int)random(-2,2);
  int oldVal = grid[(x+cellsX+newX)%cellsX][(y+cellsY+newY)%cellsY];
  grid[(x+cellsX+newX)%cellsX][(y+cellsY+newY)%cellsY] = grid[x][y];
  grid[x][y] = oldVal;
}
